package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.HotArticleService;
import com.heima.common.redis.CacheService;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.vos.ApArticleVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author jack
 * @data 2024 14:42
 */
@Service
@Slf4j
public class HotArticleServiceImpl implements HotArticleService {
    @Autowired
    private ApArticleMapper apArticleMapper;
    @Autowired
    private CacheService cacheService;

    /**
     * 计算热点文章
     */
    @Override
    public void computeHotArticle() {
        //1. 查询前5天文章
        Date fiveDaysAgo = new Date(System.currentTimeMillis() - (1000L * 60 * 60 * 24 * 5));
        LambdaQueryWrapper<ApArticle> wrapper = Wrappers.<ApArticle>lambdaQuery().ge(ApArticle::getPublishTime, fiveDaysAgo);
        List<ApArticle> apArticleList = apArticleMapper.selectList(wrapper);

        //2. 给文章算分
        if (apArticleList != null && apArticleList.size() > 0) {
            List<ApArticleVo> articleVoList = computeScore(apArticleList);

            //3. 针对每个频道进行文章的分数排名   -- 前30名存入redis
            //3.1 拿到所有的频道
            List<Integer> channelIds = apArticleList.stream().map(ApArticle::getChannelId).distinct().collect(Collectors.toList());

            //3.2 按频道进行分组统计
            for (Integer channelId : channelIds) {
                //拿到当前频道下的所有文章
                List<ApArticleVo> articleVosInSameChannel = articleVoList.stream().filter(vo -> vo.getChannelId().equals(channelId)).collect(Collectors.toList());
                //对这些文章按分排序 -- 按分数降序
                articleVosInSameChannel = articleVosInSameChannel.stream().sorted(new Comparator<ApArticleVo>() {
                    @Override
                    public int compare(ApArticleVo o1, ApArticleVo o2) {
                        return o2.getScore() - o1.getScore();
                    }
                }).collect(Collectors.toList());

                //取前30条存入redis
                List<ApArticleVo> top30InSameChannel = articleVosInSameChannel.stream().limit(30).collect(Collectors.toList());

                //存入redis
                cacheService.set("hot_article_"+channelId, JSON.toJSONString(top30InSameChannel));
            }


            //4. 针对“推荐”频道进行文章的分数排名   -- 前30名存入redis
            //对所有文章按分排序 -- 按分数降序
            articleVoList = articleVoList.stream().sorted(new Comparator<ApArticleVo>() {
                @Override
                public int compare(ApArticleVo o1, ApArticleVo o2) {
                    return o2.getScore() - o1.getScore();
                }
            }).collect(Collectors.toList());

            //取前30条存入redis
            List<ApArticleVo> top30 = articleVoList.stream().limit(30).collect(Collectors.toList());

            //存入redis
            cacheService.set("hot_article__all__", JSON.toJSONString(top30));
        }
    }

    //给文章算分
    private List<ApArticleVo> computeScore(List<ApArticle> apArticleList) {
        if (apArticleList != null && apArticleList.size() > 0) {

            List<ApArticleVo> vos = new ArrayList<>();

            for (ApArticle article : apArticleList) {
                int score = 0;

                //阅读权重：1
                Integer views = article.getViews();
                if (views != null && views > 0) {
                    score += views;
                }
                //点赞权重：3
                Integer likes = article.getLikes();
                if (likes != null && likes > 0) {
                    score += (likes * 3);
                }
                //评论权重：5
                Integer comment = article.getComment();
                if (comment != null && comment > 0) {
                    score += (comment * 5);
                }
                //收藏权重：8
                Integer collection = article.getCollection();
                if (collection != null && collection > 0) {
                    score += (collection * 8);
                }

                ApArticleVo vo = new ApArticleVo();
                BeanUtils.copyProperties(article, vo);
                vo.setScore(score);

                vos.add(vo);
            }

            return vos;

        } else {
            return null;
        }
    }


}
